contents
객체지향 프로그래밍에서 자주 쓰이는 디자인 패턴들을 설명하겠습니다. 디자인 패턴은 크게 생성 패턴(Creational), 구조 패턴(Structural), 행위 패턴(Behavioral) 세 가지로 나눌 수 있습니다.
1. 생성 패턴 (Creational Patterns)
- 목적: 객체 생성에 관련된 패턴으로, 객체 생성 과정을 캡슐화해 객체 생성 방식을 유연하게 관리합니다.
주요 생성 패턴
-
싱글톤(Singleton)
- 애플리케이션 내 오직 하나의 객체만 생성되도록 보장하는 패턴.
- 전역 접근 가능한 인스턴스를 제공합니다.
-
팩토리 메서드(Factory Method)
- 객체 생성 인터페이스를 정의하고, 실제 생성은 서브클래스에서 결정하게 하는 패턴.
- 생성과 사용 코드를 분리해 확장에 용이합니다.
-
추상 팩토리(Abstract Factory)
- 관련된 객체들을 묶어 생성할 수 있는 인터페이스 제공.
- 제품군이 여러 종류일 때 유용합니다.
-
빌더(Builder)
- 복잡한 객체를 단계별로 생성할 수 있게 하며, 생성과 표현을 분리합니다.
-
프로토타입(Prototype)
- 기존 객체를 복사(clone)해 새로운 객체를 만드는 패턴.
- 객체 생성 비용이 클 때 활용합니다.
2. 구조 패턴 (Structural Patterns)
- 목적: 클래스나 객체를 조합해 더 큰 구조를 만들거나 인터페이스를 일관되게 만드는 패턴.
주요 구조 패턴
-
어댑터(Adapter)
- 호환되지 않는 인터페이스끼리 연결하는 역할을 하는 래퍼 클래스 제공.
-
브릿지(Bridge)
- 구현부와 추상층을 분리해 독립적으로 확장 가능.
-
컴포지트(Composite)
- 단일 객체와 복합 객체를 동일하게 다룰 수 있게 트리 구조를 만들기 위한 패턴.
-
데코레이터(Decorator)
- 객체에 기능을 동적으로 추가할 수 있도록 래핑.
-
퍼사드(Facade)
- 복잡한 서브시스템을 단순한 인터페이스로 감싸 사용을 쉽게 만듭니다.
-
플라이웨이트(Flyweight)
- 공유 객체를 최대한 활용해 메모리 사용 효율을 극대화.
-
프록시(Proxy)
- 다른 객체에 대한 대리자 역할, 접근 제어나 로딩 지연 등을 구현.
3. 행위 패턴 (Behavioral Patterns)
- 목적: 객체들 간의 상호작용과 책임 분배를 단순화하는 패턴.
주요 행위 패턴
-
옵저버(Observer)
- 객체 상태 변화 시 관련 객체들에게 자동 통보.
-
전략(Strategy)
- 알고리즘을 캡슐화해 실행 중에 교체 가능.
-
커맨드(Command)
- 요청을 객체로 캡슐화, 큐에 저장하거나 실행 지연 가능.
-
상태(State)
- 상태에 따라 객체 행동을 변경.
-
책임 연쇄(Chain of Responsibility)
- 여러 객체가 순차적으로 요청 처리 가능.
-
방문자(Visitor)
- 객체 구조를 순회해 연산을 수행.
-
인터프리터(Interpreter)
- 문법 해석 및 평가 기능 제공.
-
메멘토(Memento)
- 객체 내부 상태 저장 및 복원.
-
중재자(Mediator)
- 객체 간 통신을 중앙 집중식으로 관리.
-
템플릿 메서드(Template Method)
- 알고리즘 골격 정의, 일부 단계 하위 클래스에서 구현.
-
이터레이터(Iterator)
- 컬렉션 요소 순차 접근 표준화.
요약
| 패턴 분류 | 주요 패턴 | 역할 및 목적 |
|---|---|---|
| 생성 패턴 | Singleton, Factory Method, Builder, Prototype | 객체 생성 과정 캡슐화 및 관리 |
| 구조 패턴 | Adapter, Composite, Decorator, Facade, Proxy | 객체 구성 및 인터페이스 단순화 |
| 행위 패턴 | Observer, Strategy, Command, State, Chain of Responsibility | 객체 간 상호작용 및 행위 관리 |
여기서는 일곱 가지 대표적인 객체지향 디자인 패턴(싱글톤, 팩토리 메서드, 옵저버)을 Java 코드로 예제로 보여드리겠습니다.
1. 싱글톤 패턴 (Singleton Pattern)
// Singleton 클래스
public class Singleton {
private static Singleton instance; // 유일한 인스턴스
private Singleton() {} // 생성자 private
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton(); // 최초 1회만 생성
}
return instance;
}
}
// 사용 예시:
Singleton s1 = Singleton.getInstance();
Singleton s2 = Singleton.getInstance();
System.out.println(s1 == s2); // true
2. 팩토리 메서드 패턴 (Factory Method Pattern)
// Product 인터페이스 및 구현체
interface Animal {
void speak();
}
class Dog implements Animal {
public void speak() { System.out.println("멍멍!"); }
}
class Cat implements Animal {
public void speak() { System.out.println("야옹!"); }
}
// 팩토리 클래스
class AnimalFactory {
public static Animal createAnimal(String type) {
if (type.equals("dog")) return new Dog();
else if (type.equals("cat")) return new Cat();
else throw new IllegalArgumentException("Unknown type");
}
}
// 사용 예시:
Animal a = AnimalFactory.createAnimal("dog");
a.speak(); // "멍멍!"
3. 옵저버 패턴 (Observer Pattern)
import java.util.*;
// 옵저버(구독자) 인터페이스
interface Observer {
void update(String news);
}
// 구독자 구현체
class NewsReader implements Observer {
private String name;
public NewsReader(String name) { this.name = name; }
public void update(String news) {
System.out.println(name + "가 뉴스를 받았습니다: " + news);
}
}
// 주제(발행자) 클래스
class NewsAgency {
private List<Observer> observers = new ArrayList<>();
public void addObserver(Observer o) { observers.add(o); }
public void removeObserver(Observer o) { observers.remove(o); }
public void notifyObservers(String news) {
for (Observer o : observers) {
o.update(news);
}
}
}
// 사용 예시:
NewsAgency agency = new NewsAgency();
observer1 = new NewsReader("홍길동");
observer2 = new NewsReader("김영희");
agency.addObserver(observer1);
agency.addObserver(observer2);
agency.notifyObservers("자바 디자인 패턴 강의 시작!");
// 홍길동가 뉴스를 받았습니다: 자바 디자인 패턴 강의 시작!
// 김영희가 뉴스를 받았습니다: 자바 디자인 패턴 강의 시작!
4. 데코레이터 패턴 (Decorator Pattern)
기존 객체에 동적으로 기능을 추가하는 패턴입니다.
// 기본 컴포넌트 인터페이스
interface Coffee {
String getDescription();
int getCost();
}
// 구체 컴포넌트
class BasicCoffee implements Coffee {
public String getDescription() { return "커피"; }
public int getCost() { return 2000; }
}
// 데코레이터
class MilkDecorator implements Coffee {
private Coffee coffee;
public MilkDecorator(Coffee coffee) { this.coffee = coffee; }
public String getDescription() { return coffee.getDescription() + "+우유"; }
public int getCost() { return coffee.getCost() + 500; }
}
// 사용 예시
Coffee coffee = new BasicCoffee();
coffee = new MilkDecorator(coffee);
System.out.println(coffee.getDescription()); // 커피+우유
System.out.println(coffee.getCost()); // 2500
5. 전략 패턴 (Strategy Pattern)
행동(알고리즘)을 객체로 분리하여 런타임에 교체하는 패턴입니다.
interface SortStrategy {
void sort(int[] arr);
}
class BubbleSort implements SortStrategy {
public void sort(int[] arr) { System.out.println("버블 정렬"); }
}
class QuickSort implements SortStrategy {
public void sort(int[] arr) { System.out.println("퀵 정렬"); }
}
class Sorter {
private SortStrategy strategy;
public Sorter(SortStrategy strategy) { this.strategy = strategy; }
public void sort(int[] arr) { strategy.sort(arr); }
}
// 사용 예시
Sorter sorter = new Sorter(new BubbleSort());
sorter.sort(new int[]{5,2,3}); // 버블 정렬
sorter = new Sorter(new QuickSort());
sorter.sort(new int[]{5,2,3}); // 퀵 정렬
6. 컴포지트 패턴 (Composite Pattern)
트리 구조 객체를 단일 객체처럼 다루고 싶을 때 사용하는 패턴입니다.
import java.util.ArrayList;
import java.util.List;
interface Component {
void show();
}
class Leaf implements Component {
private String name;
public Leaf(String name) { this.name = name; }
public void show() { System.out.println(name); }
}
class Composite implements Component {
private List<Component> children = new ArrayList<>();
public void add(Component c) { children.add(c); }
public void show() {
for (Component c : children)
c.show();
}
}
// 사용 예시
Composite root = new Composite();
root.add(new Leaf("Leaf1"));
Composite branch = new Composite();
branch.add(new Leaf("Leaf2"));
branch.add(new Leaf("Leaf3"));
root.add(branch);
root.show(); // Leaf1, Leaf2, Leaf3
7. 퍼사드 패턴 (Facade Pattern)
여러 복잡한 서브시스템을 간단한 인터페이스로 감싸주는 패턴입니다.
class Cpu { void start() { System.out.println("CPU 시작"); } }
class Memory { void load() { System.out.println("메모리 로드"); } }
class ComputerFacade {
private Cpu cpu = new Cpu();
private Memory memory = new Memory();
public void start() {
cpu.start();
memory.load();
System.out.println("컴퓨터 동작");
}
}
// 사용 예시
ComputerFacade computer = new ComputerFacade();
computer.start(); // CPU 시작, 메모리 로드, 컴퓨터 동작
references